﻿using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Collections;
using System.Threading;

using sfsocket.corelib.message;


namespace sfsocket.corelib.connection.client
{
    public class ChatClientReadThread
    {
        private ChatClientConnection m_Connection;
        private Thread m_Thread;
        private Queue m_Queue = Queue.Synchronized(new Queue());
        private bool m_IsStarted = false;

        public bool IsStarted
        {
            get { return m_IsStarted; }
            set { m_IsStarted = value; }
        }

        public Queue Queue
        {   
            get{ return m_Queue; }
        }

        public ChatClientReadThread(ChatClientConnection con)
        {
            m_Connection = con;
        }

        public void Start()
        {
            if (!m_IsStarted)
            {
                m_Thread = new Thread(new ThreadStart(_Worker));
                //_Thread.Name = "ReadThread :" + _Client.Client.LocalEndPoint.ToString();
                //_Thread.IsBackground = true;
                m_Thread.Start();
                m_IsStarted = true;
            }
        }

        public void Stop()
        {
            if (m_IsStarted)
            {
                m_Thread.Abort();
                m_IsStarted = false;
                try
                {
                    m_Connection.Disconnect();
                }
                catch (Exception ex)
                {
                    TraceMsg(ex.Message);
                }
            }
        }

        /// <summary>
        /// read data, encode into message, and enqueue message
        /// </summary>
        private void _Worker()
        {
            TraceMsg("Entering Read Worker Thread");
            //try
            //{
                try
                {
                    NetworkStream sr = m_Connection.GetStream();
                    while (true)
                    {
                        // read length
                        byte[] lenbuf = new byte[4];
                        sr.Read(lenbuf, 0, 4);
                        int len = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(lenbuf, 0));

                        // read type
                        byte[] typebuf = new byte[4];
                        sr.Read(typebuf, 0, 4);
                        int msgtype = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(typebuf, 0));

                        // read data
                        byte[] databuf = new byte[len - 4];
                        int nleft = len - 4;
                        int idx = 0;
                        int ret = 0;
                        while (nleft > 0)
                        {
                            ret = sr.Read(databuf, idx, nleft);
                            idx += ret;
                            nleft -= ret;
                        }
                        TraceMsg(Encoding.ASCII.GetString(databuf));

                        // parse message, but just use the raw message type, now all the mssage 
                        // type hiarchy have been lost, you can't downcast it to other subtype.
                        RawMessage smsg = new RawMessage(msgtype, databuf);
                        if (smsg != null)
                        {
                            m_Queue.Enqueue(smsg);
                            // TraceMsg("Receiving Message, Total Message" + m_Queue.Count);
                            //smsg.Dump();
                        }
                        Thread.Sleep(50);
                    }

                }
                catch (ThreadAbortException ex)
                {
                    Console.WriteLine(ex.Message);
                    Thread.ResetAbort();
                    throw ex;
                }
                catch (Exception ex)
                {
                    TraceMsg(ex.Message);
                    throw ex;
                }
        }

        private static void TraceMsg(string msg)
        {
            Console.WriteLine("[{0,3}] - {1} : {2}",
                    Thread.CurrentThread.ManagedThreadId,
                    DateTime.Now.ToString("HH:mm:ss.ffff"), msg);
        }
    }


    public class ReadThreadTest
    {
        /// <summary>
        /// test thread and queue message
        /// </summary>
        public static void TestListenThread()
        {
            TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 1080);
            listener.ExclusiveAddressUse = false;
            listener.Start();
            Console.WriteLine("Listening on port 1080...");

            // send message. thread 
            //for (int i = 0; i < 30; i++ )
                startSendThread();

            TcpClient clientB = listener.AcceptTcpClient();
            Console.WriteLine("Not implemented!");
            // SFConnection con = new SFServerConnection(clientB);
            // ChatClientReadThread readthread = new ChatClientReadThread(con);
            // readthread.Start();
        }

        private static void startSendThread()
        {
            Thread t1 = new Thread(delegate() {
                TcpClient clientA = new TcpClient("127.0.0.1", 1080);
                NetworkStream ns = clientA.GetStream();

                //// send normal SFMessage
                //for (int i = 0; i < 3; i++ )
                //{
                //    //Thread.Sleep(1000);

                //    byte[] buf = new byte[4] { 0x01, 0x02, 0x03, 0x04 };
                //    BaseMessage smsg = new BaseMessage(0x01, buf);
                //    ns.Write(smsg.GetBytes(), 0, smsg.GetBytes().Length);

                //    Console.WriteLine("send message");
                //}

                //// send FileDataMessage
                //for (int i = 0; i < 3; i++)
                //{
                //    //Thread.Sleep(1000);

                //    byte[] filedata = new byte[] { 0xff, 0xff, 0xff, 0xff };
                //    BaseMessage fmsg3 = new FileDataMessage("phone.txt", filedata);

                //    ns.Write(fmsg3.GetBytes(), 0, fmsg3.GetBytes().Length);

                //    Console.WriteLine("send filedata");
                //}

            });
            t1.Start();

        }
    }
}